package com.xkh.socket.socketio;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author xkh
 * 2020/9/17
 */
@Service
@Slf4j
public class SocketIoConnect {

    /**
     * 用来存已连接的客户端
     */
    private static Map<String, SocketIOClient> clientMap = new ConcurrentHashMap<>();

    @Autowired
    private SocketIOServer socketIOServer;

    /**
     * PostConstruct在构造函数之后执行，在Init()方法之前执行
     * Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
     */
    @PostConstruct
    private void autoStartup() {
        start();
    }

    /**
     * Spring IoC容器在销毁SocketIOServiceImpl Bean之前关闭,避免重启项目服务端口占用问题
     */
    @PreDestroy
    private void autoStop() {
        stop();
    }

    public void start() {
        //监听客户端连接
        socketIOServer.addConnectListener(client -> {
            String uid = getParamsByClient(client);
            if (uid != null) {
                clientMap.put(uid, client);
                log.info("有新客户端连接UID：{}", uid);
            }
            //给客户端发送一条信息 发送ClientReceive事件 需要客户端绑定此事件即可接收到消息
            JSONObject jsonObject = new JSONObject();
            jsonObject.append("name", "goat");
            jsonObject.append("message", "hello client");
            client.sendEvent("ClientReceive", jsonObject);
        });
        //监听客户端断开连接
        socketIOServer.addDisconnectListener(client -> {
            String uid = getParamsByClient(client);
            if (uid != null) {
                clientMap.remove(uid);
                client.disconnect();
            }
            log.info("一条客户端连接中断");
        });
        //处理自定义的事件，与连接监听类似,业务层
        socketIOServer.addEventListener("ServerReceive", JSONObject.class, (client, data, ackSender) -> {
            JSONObject jsonObject = data;
            String uid = getParamsByClient(client);
            if (uid != null) {
                log.info("接收到SID:{}发来的消息:{}", uid, jsonObject.toString());
            }
            Integer server = jsonObject.getInt("server");
            if (ObjectUtil.isNotNull(server)) {
                switch (server) {
                    case 1:
                        jsonObject.append("message", "请问你需要叫醒服务吗");
                        break;
                    case 2:
                        jsonObject.append("message", "请问你需要支付服务吗");
                        break;
                    case 3:
                        jsonObject.append("message", "请问你需要做饭服务吗");
                        break;
                    default:
                        jsonObject.append("message", "暂无此服务");
                        break;
                }
                client.sendEvent("ClientReceive", jsonObject);
            }
        });
        socketIOServer.start();
        log.info("socket.io初始化服务完成");

    }

    public void stop() {
        if (socketIOServer != null) {
            socketIOServer.stop();
            socketIOServer = null;
        }
        log.info("socket.io服务已关闭");
    }

    /**
     * 此方法为获取client连接中的参数，可根据需求更改
     *
     * @return
     * @Param client
     */
    private String getParamsByClient(SocketIOClient client) {
        //从请求的连接中拿出参数 (这里的sid必须是唯一标识)
        Map<String, List<String>> params = client.getHandshakeData().getUrlParams();
        List<String> list = params.get("UID");
        if (list != null && list.size() > 0) {
            return list.get(0);
        }
        return null;
    }
}
